-module(web_loop).
-export([loop/3]).

loop(Req, DocRoot, ProtoMaps) ->
    try
        "/" ++ Path = Req:get(path),
        case Req:get(method) of
            'GET' ->
                case Path of
                    "" ->
                        Req:serve_file("index.html", DocRoot);
                    "test" ->
                        Req:serve_file("test.html", DocRoot);    
                    _ ->
                        Req:serve_file(Path, DocRoot)
                end;
            'POST' ->
                case maps:is_key(Path, ProtoMaps) of
                    false-> Req:not_found();
                    true -> handle_msg(Req, maps:get(Path, ProtoMaps))
                end;
             _     ->
                Req:respond({501, [], []})
        end
    catch
        Type:What ->
            Report = ["web request failed", {type, Type}, {what, What}, {trace, erlang:get_stacktrace()}],
            error_logger:error_report(Report),
            Req:respond({500, [{"Content-Type", "text/plain"}], "request failed, sorry\n"})
    end.

handle_msg(Req, ProtoOpts) ->
    RqBinData = Req:recv_body(),
    Decoder = maps:get(decoder, ProtoOpts),
    {ok, RqMsg} = Decoder:decode(RqBinData),
    Handler = maps:get(handler, ProtoOpts),
    Rs = Handler:handler(ProtoOpts, RqMsg),
    case Rs of
        {ok, RsMsg} ->
            do_send_msg(Req, ProtoOpts, RsMsg);
        {error, Reason} ->
            do_send_msg(Req, ProtoOpts, Reason)
    end.

do_send_msg(Req, ProtoOpts, RsBinData) when is_binary(RsBinData) ->
    ContentType = maps:get(content_type, ProtoOpts),
    Req:respond({200, ContentType, RsBinData});
do_send_msg(Req, ProtoOpts, RsBinData) when is_map(RsBinData) ->
    Encoder = maps:get(encoder, ProtoOpts),
    {ok, RsBinData1} = Encoder:encode(RsBinData),
    do_send_msg(Req, ProtoOpts, RsBinData1);
do_send_msg(Req, ProtoOpts, RsBinData) when is_tuple(RsBinData) ->
    Encoder = maps:get(encoder, ProtoOpts),
    {ok, RsBinData1} = Encoder:encode(RsBinData),
    do_send_msg(Req, ProtoOpts, RsBinData1).